Skip to content

test(e2e): add Playwright end-to-end tests and CI - #1

Merged
NagariaHussain merged 13 commits into
mainfrom
feat/e2e-playwright-tests
Jul 8, 2026
Merged

test(e2e): add Playwright end-to-end tests and CI#1
NagariaHussain merged 13 commits into
mainfrom
feat/e2e-playwright-tests

Conversation

@NagariaHussain

Copy link
Copy Markdown
Contributor

Why?

The Vue SPA has no automated end-to-end coverage — it's only checked manually. This ports the Playwright harness from the hive app so booking/venue flows are tested in a real browser, in CI.

What?

  • Root package.json + playwright.config.ts (Playwright, setup + chromium projects).
  • e2e/ — Frappe REST/auth helpers, admin auth setup, and a public-venue smoke spec (/v/e2e-arena).
  • apna_slot/e2e_seed.py — idempotent seed: a Published venue + active resource.
  • .github/workflows/ui-tests.yml — spins up a bench, seeds, starts the server, runs the tests, uploads the report.

How?

CI builds a site apnaslot.test, runs the seed, bench start, then npx playwright test. Browser reaches *.localhost/*.test via Chromium --host-resolver-rules + an /etc/hosts entry; Node API calls go to 127.0.0.1 with a Host header. Verified locally: 2/2 passing.

🤖 Generated with Claude Code

NagariaHussain and others added 13 commits July 7, 2026 22:10
Full venue-side schema, roles, permissions, and the publisher SPA at /manage.

- DocTypes: full Venue (7 new fields + gallery/exceptions/pricing child tables,
  tab/column breaks) + Venue Resource category/sort_order; 3 new child DocTypes
- Venue Publisher role via pre-model-sync patch; become_publisher onboarding
- venue.py: unique-slug de-dupe, seed 7 weekday rows, publish/unpublish guards
- permissions.py: venue_query/venue_resource_query + has_permission, wired in hooks
- api/publisher.py: get_current_publisher, become_publisher, publish/unpublish
- SPA: /manage My Venues + venue editor (Details/Resources/Availability/Pricing/
  Gallery/Publish); one www page serves /v and /manage
- Tests: slug uniqueness, publish guards, cross-publisher isolation (17 total green)

Deviations from spec (reconciled in specs/): publisher app at /manage not /app
(Desk collision); frappe-ui 0.1.278 uses confirmDialog + Dialog v-model; doc I/O
via imperative call('frappe.client.*'); publish wrappers accept str|int names.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Full pricing engine (additive surcharge loop over day-type + time-band) and
slot engine gains exceptions (Closed / Special Hours override), midnight
crossing, and past-slot filtering. Public API returns a guest-safe venue
payload (gallery + details, no publisher/draft leak) and guards get_slots to
Published venues + Active resources.

Rebuilt public /v/:slug page into VenueHero + SlotGrid + SelectionCart with a
client-side multi-slot cart spanning resources/dates; Book CTA carries the
selection to a /v/:slug/book stub (real checkout is Phase 3).

13 new tests (30 total green); agent-browser e2e verifies weekend-evening
price stacking, Closed/Special-Hours days, and the unpublished "not available"
path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
End-to-end booking: select multiple slots, hold them together for 10
minutes, pay once through a mock gateway, get a Confirmed order that
locks every slot. All-or-nothing on the slot_key unique index; lapsed
holds are freed by a per-minute scheduler.

- Booking.validate derives end_time + amount (pricing engine) + slot_key
- BookingOrder.recompute_total / sync_status move order + lines together
- hold_slots (validate, all-or-nothing, taken list), confirm_payment
  (guards), create_account_from_order, get_order
- tasks.expire_holds (cron * * * * *) frees lapsed holds + fails payment
- Checkout, MockGateway (10-min countdown), Confirmation pages + routes
- 7 new tests (37 total green); agent-browser e2e green

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Completes the MVP with the three launch extras.

Part A — Email confirmations: Booking Order on_update doc_event fires only on
the real Held->Confirmed transition and enqueues one customer + one publisher
email listing every slot; sending is best-effort so a mail outage never fails a
paid booking.

Part B — Reviews & ratings: new Venue Review DocType (Rating stored as a 0-1
fraction, booking unique), gated create_review (guest-allowed; Confirmed + owner
+ one-per-booking), and get_public_venue now returns avg_rating/review_count/
latest reviews. Frontend StarRating widget, venue-page review list, and a
confirmation-page review form.

Part C — Publisher dashboard: get_publisher_dashboard aggregates own-venue
totals (today/week bookings, week/month revenue, upcoming, per-venue breakdown);
Booking/Booking Order/Venue Review gain permission_query_conditions +
has_permission scoping and Venue Publisher read perms; SPA /manage/dashboard and
/manage/bookings (grouped-by-order + venue/status filters) with nav.

12 new tests (49 total green); agent-browser e2e verified.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rewrite the deferred grab-bag into ordered tracer-bullet sub-phases,
each with goal/backend/frontend/tests/acceptance. Order: marketplace,
My Bookings, notification channels first (no payment work); real
payments then unblocks cancellation/refunds and monetization;
per-resource schedules and hardening last. Update PROGRESS + README.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ralph.sh feeds prompt.md to Claude Code in a loop (implement thinnest
next slice), then runs qa_prompt.md to review the last commit into
REVIEWS.md; stops on 'complete'.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Public marketplace listing so customers discover venues beyond a shared link.

- search_venues(city, q, start, page_length) + list_cities() (allow_guest,
  Published-only, card payload; text search over name/city; no publisher/draft leak)
- home_page = "v" serves the SPA at the site root
- Browse.vue (card grid + city filter + search) + browse/VenueCard.vue; router `/`
- 4 new tests (53 total green); agent-browser e2e green

Thinnest slice: city filter + text search live. category/date filters, pagination
UI and a separate /search route deferred to the next widening.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Problem
QA review of the marketplace browse slice flagged an N+1 review query with
an unbounded page_length on a guest endpoint, a search box with no debounce
and a stale-response race, a deprecated get_all param, and an unused currency
field on the card.

## Solution
- search_venues caps page_length at 50 and computes avg/count with one grouped
  _review_summaries query (Avg/Count GROUP BY venue) instead of a per-venue N+1
- get_all uses limit= (drops deprecated page_length=)
- drop unused currency from the card payload
- Browse.vue debounces the query watcher (300ms), loads city immediately, and
  drops stale responses via a monotonic token

9/9 test_public_api green; grouped avg verified live; frontend rebuilt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Port hive's Playwright harness into apna_slot: root package.json +
playwright.config.ts, e2e/ helpers and admin auth setup, an idempotent
seed (apna_slot/e2e_seed.py) creating a Published venue + resource, a
public-venue smoke spec, and a UI Tests GitHub Actions workflow that
spins up a bench, seeds, starts the server, and runs the tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace boilerplate README with a full app README: table of contents,
customer and publisher screenshots, how-it-works (slot locking, pricing,
holds), data model, tech stack, structure, install/run/test and roadmap.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fix Frappe Linter CI job: replace ambiguous unicode dashes in
comments/docstrings/strings with ASCII, swap single-element slice for
next(iter(...)) (RUF015), and apply ruff-format + prettier formatting
across the app and frontend.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- get_order: guest confirmation endpoint reads its own order by id
- e2e_seed commit: seed script run via `bench execute` must persist

Both suppressed with `# nosemgrep` per frappe-semgrep-rules convention.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A `# nosemgrep: <text>` colon form is parsed as a rule-id list, so it
suppressed nothing. Move the justification to the preceding line and
keep a bare `# nosemgrep`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@NagariaHussain
NagariaHussain merged commit 0aaea4c into main Jul 8, 2026
4 checks passed
@NagariaHussain
NagariaHussain deleted the feat/e2e-playwright-tests branch July 8, 2026 14:44
NagariaHussain added a commit that referenced this pull request Jul 13, 2026
Address all 6 findings from the "My Bookings" QA review:
- #1: add UI entry points — Browse header "My bookings" link when
  authenticated + "View my bookings" on the confirmation page
- #2: batch venue/line/resource lookups (no N+1) + limit order fetch to 100
- #3: guard _first_slot against a line-less order (no min([]) 500)
- #4: MyBookings.vue catches load failure → error state, not empty state
- #5: drop the unused confirmed_on from the order payload
- #6: add /my bare route rule + vue-router /my → /my/bookings redirect

4/4 customer API tests green, full app 57/57 green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant